;; created 2008


;; .emacs就是一个程序，这意味着：
;; * 如果太大，就需要拆开，分成多个函数，甚至多个文件
;; * 它也要有自己的配置文件（将变动部分与不变部分分离）
;; * 需要进行版本控制


;; .emacs作为一个程序的目标：
;; * 跨平台（windows，linux，cygwin）
;; * 环境自适应（有什么包配什么包，不要配不存在的包而导致出错；用户可以启用或禁用某个包；用户可以选择用该包的哪个版本）
;; * 启动快速: 按需加载插件
;; * 易扩充，易维护


;; 本.emacs为零碎功能绑定的按键汇总：
;; C-f8		insert key sequence
;; f4		rebuild and reload BROWSE generated by ebrowse
;; f2		切换行间距大小


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;  以下是实现部分  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; 为了加快启动速度，注释掉，需要时再通过C-x C-e执行吧
;; (add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/") t)
;; (add-to-list 'package-archives '("org" . "http://orgmode.org/elpa/") t)
;; (add-to-list 'package-archives '("marmalade" . "http://marmalade-repo.org/packages/")) ; 据说已经不维护了

;; 还是清华的镜像快 https://mirrors.tuna.tsinghua.edu.cn/help/elpa/
(setq package-archives '(
                         ("gnu" . "https://elpa.gnu.org/packages/")
                         ;;("gnu"   . "http://mirrors.tuna.tsinghua.edu.cn/elpa/gnu/")
                         ;; ("melpa" . "http://mirrors.tuna.tsinghua.edu.cn/elpa/melpa/")
                         ;;("stable-melpa" . "http://mirrors.tuna.tsinghua.edu.cn/elpa/stable-melpa/")
                         ("melpa" . "https://melpa.org/packages/")
                         ;;("melpa-stable" . "https://stable.melpa.org/packages/")
                         ))

;; 如果上边的某个网站不能访问，可以使用以下的代理
;; (setq url-proxy-services '(("no_proxy" . "^\\(localhost\\|10.*\\)") ("http" . "127.0.0.1:1978") ("https" . "127.0.0.1:1978")))


;; 确保在配置各个包之前先加载这些包
(setq package-enable-at-startup nil)
(package-initialize)

;; 程序主入口(main entry)在本文件最后


;; 一些外部包所在位置的默认值：
;; 可根据实际情况在~/.emacs.d/env.el中对这些位置进行调整（此文件在各个机子间不进行同步）。
;; 如果一个包的.el文件有自己独立的目录，就指向该目录；
;; 如果一个包的.el文件与其他包的.el文件共享同一个目录，则指向能表明该包存在的某个.el文件。
(defvar epm-path "~/work/epm/")
(defvar ibus-path "~/.emacs.d/packages/ibus.el/")
(defvar haskell-mode-path "~/non-exist") ; http://www.haskell.org/haskellwiki/Haskell_mode_for_Emacs
(defvar xcscope-path "/usr/local/share/emacs/site-lisp/xcscope.el") ; 从源里安装的话xcscope.el就位于此处
(defvar auctex-path "/usr/local/share/emacs/site-lisp/auctex.el")
(defvar org-path "~/.emacs.d/packages/org-mode/") ; git clone git://orgmode.org/org-mode.git
(defvar color-theme-path "~/.emacs.d/packages/color-theme/") ; http://www.nongnu.org/color-theme/
(defvar ntcmd-path "~/.emacs.d/packages/ntcmd.el") ; http://www.emacswiki.org/emacs/DosScripts
(defvar powershell-path "~/.emacs.d/packages/Powershell.el") ; http://www.emacswiki.org/emacs/PowerShell
(defvar powershell-mode-path "~/.emacs.d/packages/powershell-mode.el") ; http://www.emacswiki.org/emacs/PowerShell
(defvar bbyac-path "~/non-exist") ; https://github.com/baohaojun/bbyac/
(defvar auto-complete-path "~/.emacs.d/packages/auto-complete") ; 此包光解开不行，还要安装，这里是安装所至目录。http://auto-complete.org/ 不过用包管理器的话就不用管这个事情
(defvar yasnippet-path "~/.emacs.d/packages/yasnippet/") ; https://github.com/capitaomorte/yasnippet
(defvar helm-path "~/non-exist")
(defvar visual-basic-mode-path "~/.emacs.d/packages/visual-basic-mode.el") ; http://xahlee.org/visual_basic/emacs_visualbasic_mode.html
(defvar markdown-mode-path "~/.emacs.d/packages/markdown-mode.el") ; http://jblevins.org/projects/markdown-mode/
(defvar paredit-path "~/.emacs.d/packages/paredit.el") ; http://emacswiki.org/emacs/ParEdit
(defvar ace-jump-mode-path "~/non-exist") ; https://github.com/winterTTr/ace-jump-mode/wiki
(defvar yaml-mode-path "~/.emacs.d/packages/yaml-mode/") ; https://github.com/yoshiki/yaml-mode
;;(defvar cmake-mode-path "/usr/share/emacs/site-lisp/cmake-mode.el")
(defvar cmake-mode-path "~/non-exist")
(defvar douban-music-mode-path "~/.emacs.d/packages/douban-music-mode.el") ; https://github.com/zhengyuli/DoubanMusic
(defvar weibo-path "~/.emacs.d/packages/weibo.emacs-master/")
(defvar unicad-path "~/emacs-config-of-mine/3rd-lisp/unicad.el")  ; https://code.google.com/p/unicad/wiki/FAQ_Chinese
(defvar web-mode-path "~/.emacs.d/packages/web-mode.el") ; http://web-mode.org/

;; 有意思的东西:
;;   用于快速编写html的emmet-mode ( https://github.com/smihica/emmet-mode )
;;   选中单词，M-x mc/mark-all-like-this，对所有出现该单词的地方进行编辑
;;   use-package https://github.com/jwiegley/use-package
;; 还需要以下这些东西:
;;   simsum from windows
;;   locate-library



(defvar my-favorite-color-theme 'light-blue)
(defvar my-favorite-terminal-color-theme 'misterioso)
(defvar windows-git-bin-path "C:/Program Files/Git/bin")


;;;; ~/.emacs.d/env.el就相当于.emacs这个程序的配置文件。
(when (file-exists-p "~/.emacs.d/env.el")
  (load-file "~/.emacs.d/env.el"))
;; 如果想禁用某个package，可在env.el中让其path指向一个不存在的位置，如(setq color-theme-path "~/non-exist")


(defun add-to-load-path (dir-or-file-path)
  (if (file-directory-p dir-or-file-path)
      (add-to-list 'load-path dir-or-file-path)
    (add-to-list 'load-path (file-name-directory dir-or-file-path))))


;; 自己下载的包优先于elpa中的包
;; elpa管理下的包地位仅次于built-in的包，可看作emacs的一部分。
(defun add-package (package dir-or-file-path)
  (cond ((file-exists-p dir-or-file-path) (add-to-load-path dir-or-file-path) t)
        ((package-installed-p package) t)
        (t (message "no %s" (symbol-name package)) nil)
        )
  )


;;;; 甄别宿主平台

;; (equal system-name "DYN-ASUS")

(defun is-term ()
  (not initial-window-system))


(defun is-win2k ()
  (and
   (equal system-type 'windows-nt)
   (eq (car (w32-version)) 5)
   (eq (cadr (w32-version)) 0)))


(defun is-winxp ()
  (and
   (equal system-type 'windows-nt)
   (eq (car (w32-version)) 5)
   (eq (cadr (w32-version)) 1)))


(defun is-vista ()
  (and
   (equal system-type 'windows-nt)
   (eq (car (w32-version)) 6)
   (eq (cadr (w32-version)) 0)))


(defun is-win7 ()
  (and
   (equal system-type 'windows-nt)
   (eq (car (w32-version)) 6)))


(defun is-win10 ()
  (and
   (equal system-type 'windows-nt)
   (eq (car (w32-version)) 10)))


(defun is-ubuntu ()
  (if (equal system-type 'gnu/linux)
      t
    nil))


(defun is-cygwin ()
  (if (equal system-type 'cygwin)
      t
    nil))

;; 参考：https://emacs.stackexchange.com/questions/47782/is-there-a-way-emacs-can-infer-is-running-on-wsl-windows-subsystem-for-linux
(defun is-wsl ()
  (if (and operating-system-release (string-match "-[Mm]icrosoft" operating-system-release)) ; operating-system-release在wsl下有值，在windows下却为nil
   t
  nil))

;;;; 加载设置（以load打头），短而简单的配置，就直接在
;;;; load函数中做了；长而复杂的配置，在load中调用相应的configure函数。
;;;; 对路径的检测放在configure函数中，因为同一个configure函数会被多处调用。
;;;; 检测路径时，如果一个插件有自己独立的目录，检测该目录是否存在即可；如与其他插件共享目录，则检测其主要文件是否存在。
(defun load-common-settings ()

  (setq frame-title-format '("%b"
                             (:eval
                              (if (buffer-file-name)
                                  (concat " ("
                                          (directory-file-name
                                           (file-name-directory
                                            (abbreviate-file-name
                                             (buffer-file-name))))
                                          ")")
                                ""))
                             " - Emacs"))

  (add-to-list 'load-path "~/emacs-config-of-mine/lisp/")
  (add-to-list 'load-path "~/emacs-config-of-mine/3rd-lisp/")
  (add-to-list 'load-path "~/emacs-config-of-mine/ws/")
  ;;(add-to-list 'load-path "~/.emacs.d/packages/")
  ;;(add-to-list 'image-load-path "~/.emacs.d/images/")
  (when (boundp 'image-load-path)
    (add-to-list 'image-load-path "~/emacs-config-of-mine/images/")
    )

  (when (file-exists-p "~/share/emacs/lisp/")
    (add-to-load-path "~/share/emacs/lisp/"))


  (require 'string-operations)
  (load "general-helper")
  (load "font-helper")
  (autoload 'bc-eval-region "bc" "bc" t)

  (require 'debug-log)
  (require 'ws)                         ; 中文分词
  (require 'pmh)
  (require 'smart-kill)


  (setq inhibit-startup-screen t)
  (setq visible-bell t)                 ; 我讨厌emacs发出声音
  (setq column-number-mode t)
  (setq scroll-bar-mode-explicit t)
  (when (boundp 'set-scroll-bar-mode)
    (set-scroll-bar-mode 'right)
    )

  (setq show-paren-mode t)
  (put 'narrow-to-region 'disabled nil)
  (require 'uniquify)
  (setq uniquify-buffer-name-style 'forward)

  ;; cua
  ;;(cua-mode)
  ;;(setq cua-prefix-override-inhibit-delay 0.1) ; default 0.2

  (iswitchb-mode t)
  (load "iswitchb-pinyin")              ; 给iswitchb-mode添加按拼音首字母匹配的能力

  (recentf-mode 1)

  ;; (which-func-mode 1) 不稳定，时而就无显示了。
  (setq read-file-name-completion-ignore-case t)
  (windmove-default-keybindings)
  (setq make-backup-files nil)
  (column-number-mode t)
  (show-paren-mode t)
  (global-set-key (kbd "C-z") 'undo)

  ;; 奇怪啊，如果写C-/，总是检测到C-_。http://www.newsmth.net/nForum/#!article/Emacs/120685
  (if (is-term)
      (global-set-key (kbd "C-_") 'suspend-frame) 
    (global-set-key (kbd "C-/") 'suspend-frame))

  (when (is-term)
    (xterm-mouse-mode))
  
  (global-set-key (kbd "C-c w") 'delete-region)
  (global-set-key (kbd "C-c k") 'server-edit)
  (setq-default indicate-empty-lines t)

  ;; tab and space
  ;; when true, emacs use mixture of tab and space to achieve offset
  (setq-default indent-tabs-mode nil)
  ;; control length used to offset.
  ;;(setq-default c-basic-offset 4)

  (setq c-default-style
        '((c++-mode . "stroustrup")
          (java-mode . "java")
          (awk-mode . "awk")
          (other . "gnu")))

  ;; control how emacs explain TAB.
  (setq-default tab-width 4)
  ;; (defun my-java-mode-hook ()
  ;;   (setq c-basic-offset 4))
  ;; (add-hook 'java-mode-hook 'my-java-mode-hook)

  ;; (add-hook 'before-save-hook 'delete-trailing-whitespace)

  ;(modify-coding-system-alist 'file "\\.txt\\'" 'utf-8-unix)
  ; 避免windows下保存含汉字文档，或者退出时ac-comphist.dat中有汉字时，emacs要求输入文件编码的问题
  (setq coding-system-for-write 'utf-8-unix)

  (global-set-key (kbd "<C-f8>") 'insert-key-sequence)

  ;; 这种方法不行，按钮添加上去了，可是过一会就消失了，而且按钮在最左边。
  ;; (define-key global-map [tool-bar new-untitled-button]
  ;;   '(menu-item "New untitled" new-untitled
  ;;               :help "New untitled!"
  ;;               :image (image :type xpm :file "new.xpm")))

  ;; 得用这种方法
  (tool-bar-add-item "new-untitled" 'new-untitled 'new-untitled-button :help "New untitled")
  (tool-bar-add-item "home" 'open-init-file 'open-init-file-button :help "Open init-file")
  (tool-bar-add-item "delete-other-windows" 'delete-other-windows 'delete-other-windows-button :help "Maximize")


  ;;(configure-helm-mode)

  (when (not (is-term))
    (configure-tabbar-mode))
  (configure-text-mode)
  (configure-org-mode)
  (configure-color-theme)
  (configure-c++-mode)
  (configure-java-mode)
  (configure-python-mode)
  (configure-emacs-lisp-mode)
  (configure-haskell-mode)
  (configure-go-mode)
  (configure-bbyac)
  (configure-auto-complete)
  (configure-yasnippet)
  (configure-markdown-mode)
  (configure-yaml-mode)
  (configure-cmake-mode)
  (configure-paredit)
  (configure-ace-jump-mode)
  (configure-calendar/diary)
  ;;(configure-weibo)
  (configure-unicad)
  (configure-web-mode)
  ;;(configure-js-mode)
  (configure-js2-mode)
  (configure-css-mode)
  (configure-tss-mode)
  (configure-ace-window)

  (when (add-package 'douban-music-mode douban-music-mode-path)
    (autoload 'douban-music "douban-music-mode" nil t))

  )


(defun load-win-common-settings ()

  (load-common-settings)
  (server-start)                        ;如果报错说"The directory
                                        ;`~/.emacs.d/server' is
                                        ;unsafe"，将文件夹server的
                                        ;owner设为当前用户。用坚果云同
                                        ;步了.emacs.d就会导致这个问题。
  (when (fboundp 'ime-set-status)
    (require 'smart-ime)
    (smart-ime-mode 1))

  ;; 自己编译的emacs，所有.el文件都被打包成.el.gz，查看源代码时需要gzip解开。gzip位于此处。
  ;;(add-to-list 'exec-path "F:/MinGW/msys/1.0/bin")

  ;;(add-to-list 'exec-path windows-git-bin-path) ; 为了避免混用linux与win下的git，先把这行屏蔽了
  

  ;;(w32-register-hot-key [M-tab]) ; win7下无效
  ;;(w32-unregister-hot-key [M-tab])
  (configure-magit)
  ;;(setq magit-git-executable "wsl git") ; 还是不行啊，C-x g时会提示找不到wsl git。看来是把wsl git当成一个命令了。其实wsl是命令，git为参数
  (configure-ntcmd-mode)
  (configure-powershell)
  (configure-powershell-mode)
  (configure-visual-basic-mode)
  (global-set-key (kbd "<C-lwindow>") 'no-op)  ; 回避win10与百度输入法组合的问题
  (global-set-key (kbd "<C-wheel-up>") 'text-scale-increase)
  (global-set-key (kbd "<C-wheel-down>") 'text-scale-decrease))


(defun load-winxp-settings ()
  (load-win-common-settings)
  (load-winxp-font-settings))


(defun load-win7-settings ()

  ;;(make-frame-invisible)
  (load-win-common-settings)
  (load-win7-font-settings)
  ;;(tool-bar-mode 1)
  ;;(tool-bar-mode -1) ; 有了这行，frame最大化就有问题。http://stackoverflow.com/questions/815239/how-to-maximize-emacs-on-windows-at-startup  可通过注册去除工具栏
  ;;(w32-send-sys-command 61488)          ; frame最大化

  ;;(make-frame-visible)
)


(defun load-linux-common-settings ()

  (load-common-settings)

  ;; add the line below to ~/.bashrc
  ;;alias emacs='XMODIFIERS=@im=none emacs'

  (configure-gdb)
  (configure-magit)

  (setq bookmark-save-flag 1)

  (configure-xcscope)

  (configure-epm)

  ;;(configure-edect) ; emacs自带的已经很好用了。
  ;;(configure-semantic) ; 没多有用，慢吞吞的
  (configure-lsp-mode)

  (configure-ggtags)

  (configure-sudo-edit)

  (global-set-key (kbd "<C-mouse-4>") 'text-scale-increase)
  (global-set-key (kbd "<C-mouse-5>") 'text-scale-decrease))


(defun load-ubuntu-settings ()

  (load-linux-common-settings)
  ;;(load-ubuntu-font-settings)


  
  ;;(configure-ibus)                 ; 并非所有linux系统的输入法都是ibus
  (configure-pyim)

  ;; 使得能够在emacs跟其他程序之间复制粘贴
  (setq x-select-enable-clipboard t)

  (configure-auctex))


(defun load-cygwin-settings ()
  (load-linux-common-settings)

  ;; need emacs compiled with smart-ime supports
  (when (fboundp 'ime-save-and-set-status)
    (require 'smart-ime)
    (smart-ime-mode 1))
  )

(defun load-wsl-settings ()
  (load-ubuntu-settings)

  ;; 共享剪贴板
  (unless window-system
    (when (getenv "DISPLAY")
      (defun xsel-cut-function (text &optional push)
        (with-temp-buffer
          (insert text)
          (call-process-region (point-min) (point-max) "fake-xsel" nil 0 nil "-b" "-i")))
      (defun xsel-paste-function()
        (let ((xsel-output (shell-command-to-string "fake-xsel -b -o")))
          (unless (string= (car kill-ring) xsel-output)
            xsel-output )))
      (setq interprogram-cut-function 'xsel-cut-function)
      ;; (setq interprogram-paste-function 'xsel-paste-function) ; 问题多多，不如用个专门的函数负责从windows粘贴
      (global-set-key (kbd "C-c C-y") 'paste-from-win-to-wsl)
      ))
  )


(defun paste-from-win-to-wsl ()
  (interactive)
  (insert (shell-command-to-string "fake-xsel -b -o"))
  (delete-backward-char 1)
  )

(defun load-term-settings ()
  (load-linux-common-settings))



;;;; 一次性的设置（以configure打头）

(defun configure-helm-mode ()
  (when (add-package 'helm helm-path)
    (require 'helm-config)
    (global-set-key (kbd "M-x") 'helm-M-x)
    (global-set-key (kbd "C-x C-f") 'helm-find-files)
    )
  )

(defun configure-org-gtd ()
  (global-set-key (kbd "C-c l") 'org-store-link)
  (global-set-key (kbd "C-c c") 'org-capture)
  ;;(global-set-key (kbd "C-c a") 'org-agenda) ; 快捷键跟ace-jump冲突
  (global-set-key (kbd "C-c b") 'org-iswitchb)

  ;; Setting up Remember for Org
  ;;(org-remember-insinuate)  ;; 24.3 says: Symbol's function definition is void: org-remember-insinuate

  ;;(setq org-directory "~/gtd")
  (setq org-default-notes-file (concat org-directory "/notes.org"))
  (define-key global-map "\C-cr" 'org-remember)

  (setq gtd-dir (concat org-directory "/gtd"))

  (setq org-agenda-span 'month)

  ;; 9.1.3 Capture templates
  (setq org-capture-templates
        `(("i" "In-basket" entry (file ,(concat gtd-dir "/in-basket.org")) "* %?\n  %i\n")
          ("I" "In-basket-with-link" entry (file ,(concat gtd-dir "/in-basket.org")) "* %?\n  %a\n  %i\n")
          ))

  (setq org-refile-targets `(((,(concat gtd-dir "/projects.org")) . (:tag . "unorganized"))
                             ((,(concat gtd-dir "/someday-maybe.org")) . (:tag . "unorganized"))
                             ((,(concat gtd-dir "/tickler.org")) . (:tag . "unorganized"))
                             ((,(concat gtd-dir "/reference-material.org")) . (:tag . "unorganized"))
                             ((,(concat gtd-dir "/trash.org")) . (:tag . "trash"))
                             )
        )

                                        ;(add-hook 'after-init-hook 'split-window-horizontally)
  (add-hook 'after-init-hook 'org-todo-list) 


  (require 'org-aided-gtd)
  (global-set-key (kbd "C-c p") 'move-to-projects)

  (setq org-enforce-todo-dependencies t) ; 确保父任务与子任务之间的依
                                        ; 赖关系、兄弟任务之间的依赖
                                        ; 关系不被打破。改变该变量的
                                        ; 取值，revert-buffer之后才
                                        ; 起效。

  ;; 只搜索那些没有DONE的一级标题，如果其或其下的子标题带有action标记，则表示项目还在推进
  (setq org-stuck-projects '("+LEVEL=1/-DONE"
                             ("TODO")
                             ("calendar" "delegated")
                             ""))

  (setq org-agenda-custom-commands
        '(
          ("w" tags "delegated")
          ))

  ;; MobileOrg
  ;; 文件保存成utf-8-unix，免得在android上乱码
  (modify-coding-system-alist 'file "\\.org\\'" 'utf-8-unix)

  ;; 跟MobileOrg在此文件夹下交换信息
  ;;(setq org-mobile-directory "C:/Users/duyanning/Ubuntu One/MobileOrg") 
  ;;(setq org-mobile-directory "F:/My Box Files/MobileOrg") 
  ;;(setq org-mobile-directory "Z:/MobileOrg") 

  ;; 执行M-x org-mobile-pull 将mobileorg.org中的内容取至此处
  (setq org-mobile-inbox-for-pull (concat gtd-dir "/in-basket.org")) 
  ;; 执行M-x org-mobile-push 将下列文件复制到信息交换文件夹
  (setq org-mobile-files `(,(concat gtd-dir "/projects.org")))

  ;; 我讨厌一push就在projects.org中自动添加很多ID properties
  (setq org-mobile-force-id-on-agenda-items nil)

  (setq safe-local-variable-values (cons '(after-save-hook . org-mobile-push) 
                                         safe-local-variable-values))  
  )

;; (configure-text-mode)
(defun configure-text-mode ()
  (add-hook 'text-mode-hook
            '(lambda ()
               (electric-pair-mode 1)
               (subword-mode 1)           ; 视大写字母为word的边界，helloWorldChina
               (ws-mode)                  ; 中文分词
               (pmh-mode)
               ;; 在汉字中启用ws-mode，在英文中启用subword-mode
               (add-hook 'pmh-hook '(lambda ()
                                      (if (looking-at "\\cc")
                                          (progn
                                            (setq subword-mode nil)
                                            (setq ws-mode t)
                                            )
                                        (setq subword-mode t)
                                        (setq ws-mode nil)))
                         nil
                         t
                         )
               
               ))
  )


(defun configure-org-mode ()
  (when (add-package 'org (concat org-path "lisp"))
    (add-package 'org-plus-contrib (concat org-path "contrib/lisp"))

    (setq org-replace-disputed-keys t)

    ;; (when (file-exists-p org-path)
    ;;   (require 'org-install))


    ;; (add-to-list 'auto-mode-alist '("\\.txt\\'" . org-mode))  ; 算了，CMakeLists.txt也会中招
    (add-to-list 'auto-mode-alist '("\\.org\\'" . org-mode)) 
    ;;(add-to-list 'auto-mode-alist '("\\.txt\\'" . orgtbl-mode))
    ;; (add-to-list 'auto-mode-alist '("\\.txt\\'" . orgstruct-mode))
    ;; (add-to-list 'auto-mode-alist '("\\.txt\\'" . orgstruct++-mode))

    ;; (global-set-key "\C-c L" 'org-insert-link-global)
    ;; (global-set-key "\C-c o" 'org-open-at-point-global)



    (setq org-src-fontify-natively t)

    (add-hook 'org-mode-hook 'tweak-org-mode)

    ;; (add-to-list 'load-path "~/org-7.5/contrib/lisp")
    ;; (require 'org-toc)
    ;; (global-set-key "\C-cs" 'org-toc-show)
    (setq org-ctrl-k-protect-subtree 'error)
    (require 'doc-struct)


    (add-hook 'pmh-hook '(lambda ()
                           (if (eq major-mode 'lisp-interaction-mode)
                               (progn
                                 (ime-save-and-set-status 0)
                                 )
                             (ime-restore-status)
                             )
                           )
              nil
              t
              )


    ;; GTD
    ;;(configure-org-gtd)


    )
  )

;; 按C-\启动pyim中文输入法(双拼)
;; https://github.com/tumashu/pyim
;; 安装pyim时，请一并安装pyim-basedict
(defun configure-pyim ()
  (when (add-package 'pyim "~/non-exist")
    (require 'pyim)
    (require 'pyim-basedict)
    (pyim-basedict-enable)
    ;; (require 'chinese-pyim-greatdict)
    ;; (chinese-pyim-greatdict-enable)

    (setq default-input-method "pyim")
    ;;(setq pyim-default-scheme 'microsoft-shuangpin)
    (pyim-default-scheme 'microsoft-shuangpin)

    ;;(global-set-key (kbd "C-;") 'toggle-input-method)

    (define-key pyim-mode-map "." 'pyim-page-next-page)
    (define-key pyim-mode-map "," 'pyim-page-previous-page)
    

    )
  )
;; (configure-pyim)


;; 我在linux mint 17.3(相当于ubuntu 14.04)下使用emacs 24.3，无法像以前那样使用ibus了
;; 据说是The interface python-ibus is broken with ibus 1.5, and the emacs interface ibus.el is non longer usable.
;; 参考 https://www.emacswiki.org/emacs/IBusMode#toc1
;; 参考 https://bugs.launchpad.net/ibus.el/+bug/1159767
;; 没办法那在linux我就用emacs的内置输入法凑合吧
(defun configure-ibus ()
  (if (not (file-exists-p ibus-path))
      (message "no ibus.el")
    (add-to-load-path ibus-path)
    (if (file-exists-p (concat ibus-path "ibus.el"))
        (require 'ibus)
      (require 'ibus "ibus-dev.el")) ; bzr库中的名为ibus-dev.el，而非ibus.el。
    ;; Turn on ibus-mode automatically after loading .emacs
    (add-hook 'after-init-hook 'ibus-mode-on)
    ;; Use C-SPC for Set Mark command
    (ibus-define-common-key ?\C-\s nil)
    ;; Use C-/ for Undo command
    ;;(ibus-define-common-key ?\C-/ nil)
    (ibus-define-common-key ?\C-z nil)
    ;; Change cursor color depending on IBus status
    (setq ibus-cursor-color '("red" "blue" "limegreen"))

    ;; use C-; to toggle IBus
    (global-set-key [(control ?\;)] 'ibus-toggle)
    ;; Enable C-; key only for preediting
    (ibus-define-common-key [(control ?\;)] nil)
    (ibus-define-preedit-key [(control ?\;)] t)))


(defun configure-gdb ()
  (setq gdb-many-windows t)
  ;;(setq gdb-show-main t)
  )


;; emacs中的git客户端
(defun configure-magit ()
  (when (add-package 'magit "~/non-exist")
    ;;(require ')
    (global-set-key (kbd "C-x g") 'magit-status)
    )
  )

;; M-x sudo-edit后就可以以root身份编辑文件。
(defun configure-sudo-edit ()
  (when (add-package 'sudo-edit "~/non-exist")
    (require 'sudo-edit)
    ;;(global-set-key (kbd "C-c C-r") 'sudo-edit)
    )
  )


(defun configure-semantic ()
  ;; 参考emacs手册Programs/Semantic一节，以及更全面的semantic手册
  ;; https://www.gnu.org/software/emacs/manual/html_node/semantic/index.html
  
  (semantic-mode 1)


  ;; Idle Scheduler
  (global-semantic-idle-scheduler-mode 1)
  ;;(global-semantic-idle-completions-mode) ; 空闲时自动补全。自动补全后可按M-p或M-n在候选之间切换。回车接受。TAB切换并接受。C-g退出。


  ;; MRU Bookmarks mode，给最近使用的tag加书签，以便返回
  ;;(global-semantic-mru-bookmark-mode 1)


  ;; Sticky Function mode，就算函数或类的名字被翻页翻上去了，仍然用一行显示出来，让你知道你在哪个函数中。
  ;; 相比which-func-mode，好处在于which-func-mode显示的名字一旦横向切分窗口可能就看不见了。
  (global-semantic-stickyfunc-mode 1)


  ;; Highlight Func Mode，不喜欢
  ;;(global-semantic-highlight-func-mode 1)


  ;; Tag Decoration Mode，把屏幕弄得花花绿绿的，不喜欢
  ;; (global-semantic-decoration-mode 1)
  ;; (semantic-toggle-decoration-style 'semantic-tag-boundary t)
  ;; (semantic-toggle-decoration-style 'semantic-decoration-on-private-members t)
  ;; (semantic-toggle-decoration-style 'semantic-decoration-on-protected-members t)
  ;; (semantic-toggle-decoration-style 'semantic-decoration-on-includes t)

  )


;; 用global在源码中定位
;; https://github.com/leoliu/ggtags
;; 使用前需要做的事情：
;;   安装好global：
;;     sudo apt install global
;;   安装好universal-ctags：# 真的需要吗？我看global自己带着universal-ctags.so
;;     sudo apt install universal-ctags #安装之前，ctags指向/usr/bin/ctags.emacs，安装后就指向/usr/bin/ctags-universal了
;;   安装好pygments ：# 高版本的global自带，也不需要了
;; 快捷键：
;;   M-.
;;   M-,
;;   C-M-.
(defun configure-ggtags ()
  (when (add-package 'ggtags "~/non-exist")
    (add-hook 'c-mode-common-hook
          (lambda ()
            (when (derived-mode-p 'c-mode 'c++-mode 'java-mode)
              (ggtags-mode 1))))
      )
  )
;; (configure-ggtags)


;; LSP server的客户端(只有在ggtags没有启用的情况下才开启lsp)
;; https://github.com/emacs-lsp/lsp-mode
;; 要想在obj.之后列出成员函数，还需要安装company-lsp这个包
;; lsp-mode跟xref配合，M-.可以去标识符的定义处，M-,可以返回原来位置。
;; 这个功能跟ggtags提供的功能重复，快捷键都一样。
;; 可能这个插件比较复杂，官网建议升级该插件的步骤：1)删除该插件 2) 重启emacs 3)安装该插件
;; C++
;;   使用前需要做的事情
;;     安装clangd
;;       参考 https://clangd.llvm.org/installation.html
;;       sudo apt install clangd-12 # 不指定版本号的话，可能会装上比较老的版本
;;       sudo update-alternatives --install /usr/bin/clangd clangd /usr/bin/clangd-12 100
;;   后记：
;;     我不想用lsp了，配置太麻烦，因为clangd本质上是个C++编译器，为了结果准确起见，最好能让它用跟你编译时用的一样的参数。
;;     https://clangd.llvm.org/installation.html 这里详细讲了如何得到这些参数
;;     这意味着我用自己的epm或cpps的话，还要为之生成一个compile_commands.json文件。cmake/xmake都会生成这个文件。
;; golang
;;   使用前需要做的事情
;;     安装gopls
;;       参考 https://github.com/golang/tools/blob/master/gopls/README.md#installation
;;       go install golang.org/x/tools/gopls@latest
;;     将gopls所在目录$HOME/go/bin加入PATH
;; 快捷键：
;;   lsp模式特定快捷键
;;     参考 https://emacs-lsp.github.io/lsp-mode/page/keybindings/
;;     s-l g g 	Find definitions of the symbol under point.
;;     s-l g r 	Find references of the symbol under point.
;;     s-l g i 	Find implementations of the symbol under point.
;;     s-l g t 	Find type definitions of the symbol under point.
;;     s-l g d 	Find declarations of the symbol under point.
;;     s-l g h 	Show the incoming call hierarchy for the symbol at point. (requires lsp-treemacs)
;;     s-l g a 	Find all meaningful symbols that match pattern.
;;     s-l h h 	Display the type signature and documentation of the thing at
;;     s-l h s 	Activate signature help.
;;     s-l h g 	Trigger display hover information popup and hide it on next typing.
;;     s-l r r 	Rename the symbol (and all references to it).
;;     s-l a h 	Highlight symbol at point.
;;     s-l G g 	Peek definitions to the identifier at point. (requires lsp-ui)
;;     s-l G r 	Peek references to the identifier at point. (requires lsp-ui)
;;     s-l G i 	Peek implementation locations of the symbol at point. (requires lsp-ui)
;;     s-l G s 	Peek symbols in the workspace. (requires lsp-ui)
;;   xref快捷键
;;     参考 file:///F:/manual/emacs/emacs/Looking-Up-Identifiers.html#Looking-Up-Identifiers
;;     M-.  去定义处
;;     M-,  返回刚才位置
;;     C-M-.  查找字符串   # windows terminal下按了没反应，且无法克服。
;;                             参考 https://github.com/microsoft/terminal/issues/6722
;;                           wsl-terminal下本地emacs正常，远程emacs有响应但却是乱码
(defun configure-lsp-mode ()
  (when (add-package 'lsp-mode "~/non-exist")
    (setq lsp-keymap-prefix "C-l")

    (require 'lsp-mode)

    ;; c++
    ;; (when (not (package-installed-p 'ggtags))
    ;;   (add-hook 'c++-mode-hook #'lsp))

    ;; golang
    (add-hook 'go-mode-hook #'lsp-deferred)
    ;; Set up before-save hooks to format buffer and add/delete imports.
    ;; Make sure you don't have other gofmt/goimports hooks enabled.
    (defun lsp-go-install-save-hooks ()
      (add-hook 'before-save-hook #'lsp-format-buffer t t)
      (add-hook 'before-save-hook #'lsp-organize-imports t t))
    (add-hook 'go-mode-hook #'lsp-go-install-save-hooks)

    
    )
  )
;; (configure-lsp-mode)


;; 纯elisp编写的在目录中查找并替换的工具
;; https://wilkesley.org/~ian/xah/emacs/elisp-xah-find-text.html
;; 支持的命令：
;;   xah-find-text
;;   xah-find-text-regex
;;   xah-find-count
;;   xah-find-replace-text
;;   xah-find-replace-text-regex
(defun configure-xah-find ()
  (when (add-package 'xah-find "~/non-exist")
    (setq xah-find-file-separator "\n")   ; ───
    (setq xah-find-occur-separator "-------------------------------------------\n")
    ;; M-x list-colors-display
    (setq xah-find-file-background-color "firebrick")
    (setq xah-find-match-background-color "chocolate")
    )
  )
;; (configure-xah-find)


(defun configure-cedect ()
  ;; according to http://alexott.net/en/writings/emacs-devenv/EmacsCedet.html
  (load-file "~/cedet-1.0/common/cedet.el")

  ;;; 工程管理。我不用它，我用我自己的epm。
  ;; (global-ede-mode 1)


  ;; 下边这5个，都是预先定义的设置。一个比一个功能多，可通过(C-h f)查看其区别。
  ;; 但这些都不符合我的需求,有些缺我要的功能，有些虽有我要的，但却包含我不想要的。
  ;; 因此，我从最小功能集合出发，然后自行定义。
  ;; (semantic-load-enable-minimum-features)
  (semantic-load-enable-code-helpers)
  ;; (semantic-load-enable-gaudy-code-helpers) ;
  ;; (semantic-load-enable-excessive-code-helpers)
  ;; (semantic-load-enable-semantic-debugging-helpers)


  ;; semantic-ia这个包能在使用时自动加载。但我们提前加载。在
  ;; (semantic-load-enable-minimum-features)及以上，semantic-ia中的命令
  ;; 就可以正常工作。
  (require 'semantic-ia)


  ;;; 在菜单栏上添加一个TAGS菜单，该功能在(semantic-load-enable-code-helpers)及以上都是默认打开的。
  ;; (add-hook 'semantic-init-hooks
  ;;           '(lambda ()
  ;;              (imenu-add-to-menubar "TAGS")))



  ;;; 名字补全。有两种途径：第一种，用semantic-ia这个包。第二种，用
  ;; Senator这个包。前者更精确，后者速度更快。(semantic-load-enable-code-helpers)会使用Senator。
  ;; 分别如下：

  ;; semantic-ia提供的三种补全方式：
  ;; M-x semantic-ia-complete-symbol 以buffer方式呈现候选名字
  ;; M-x semantic-ia-complete-symbol-menu 以菜单方式呈现候选名字
  ;; M-x semantic-ia-complete-tip 以tooltip方式呈现候选名字

  ;; Senator提供的三种补全方式
  ;; M-x senator-complete-symbol 以buffer方式呈现候选名字 (C-c , TAB)
  ;; M-x senator-completion-menu-popup 以菜单方式呈现候选名字 (C-c , SPC)

  ;; 我想把本来绑定在Senator身上的两个键(C-c , TAB)和(C-c , SPC)绑定到semantic-ia中的对应物上，但是改不了。
  ;; 可能是受emacs自带的cedet功能影响吧。于是绑到(C-c TAB)和(C-c SPC)上。感觉效果并没有想象中的好。
  ;; (add-hook 'c-mode-common-hook
  ;;           '(lambda ()
  ;;              (local-set-key (kbd "C-c TAB") 'semantic-ia-complete-symbol)
  ;;              ;(local-set-key (kbd "C-c SPC") 'semantic-ia-complete-tip)
  ;;              (local-set-key (kbd "C-c SPC") 'semantic-ia-complete-symbol-menu)))



  ;; c模式下，按.或>之后，呈现补全候选
  (add-hook 'c-mode-common-hook
            '(lambda ()
               (local-set-key "." 'semantic-complete-self-insert)
               (local-set-key ">" 'semantic-complete-self-insert)))



  ;;; 打开srecode小模式，以便插入代码模板
  ;(global-srecode-minor-mode 1)            ; Enable template insertion menu

  )


(defun configure-auctex ()
  (if (not (file-exists-p auctex-path))
      (message "no auctex")
    (add-to-load-path auctex-path)
    (load "auctex.el" nil t t)
    (load "preview-latex.el" nil t t)
    (setq TeX-auto-save t)
    (setq TeX-parse-self t)
    (setq-default TeX-master nil)


    ;; 用xetex引擎而不是默认的引擎（xetex对中文字体的支持好）
    (setq TeX-engine 'xetex)

    ;; 产生pdf而不是dvi
    (setq TeX-PDF-mode t)

    (add-hook 'TeX-mode-hook 'tweak-TeX-mode)



    ;; ubuntu 10.04的evince版本太老，不支持从pdf切换到latex中对应点。
    ;; 而又无法为其安装高版本的evince。所以用来自KDE的okular作为pdf阅读器。
    ;; okular命令行选项
    ;; --unique让okular复用同一个进程。
    ;; %打头的占位符的含义请参考变量TeX-expand-list的文档
    ;; %n TeX-current-line
    ;; %b TeX-current-file-name-master-relative
    (setq TeX-view-program-list '(("Okular"
                                   ("okular"
                                    (mode-io-correlate " --unique %o#src:%n%b")))))


    ;; 把上边定义的okular程序放在列表最前面，如果输出是pdf，就使用okular
    ;; (setq TeX-view-program-selection
    ;;       (cons '(output-pdf "Okular") TeX-view-program-selection))
    (setq TeX-view-program-selection '((output-pdf "Okular")))


    ))


(defun configure-color-theme ()
  (if (is-term)
      (load-theme my-favorite-terminal-color-theme t)
    (load-theme my-favorite-color-theme t))
  
  ;; (load-theme 'adwaita t)
  ;; (load-theme 'deeper-blue t)           ;
  ;; (load-theme 'dichromacy t)
  ;; (load-theme 'light-blue t)
  ;; (load-theme 'manoj-dark t)            ;
  ;; (load-theme 'misterioso t)
  ;; (load-theme 'tango t)
  ;; (load-theme 'tango-dark t)            ;
  ;; (load-theme 'tsdh-dark t)             ;
  ;; (load-theme 'tsdh-light t)
  ;; (load-theme 'wheatgrass t)            ;
  ;; (load-theme 'whiteboard t)
  ;; (load-theme 'wombat t)                ;

  )
;; for emacs 23
;; (defun configure-color-theme ()
;;   (if (not (file-exists-p color-theme-path))
;;       (message "no color-theme")
;;     (add-to-load-path color-theme-path)
;;     (require 'color-theme)

;;     ;; 我自己收集的color themes都放在~/.emacs.d/packages/my-color-themes/下，或者有其独立目录，或者没有，通通加入laod-path。
;;     (add-to-list 'load-path "~/.emacs.d/packages/my-color-themes/")
;;     (let ((default-directory "~/.emacs.d/packages/my-color-themes/"))
;;       (normal-top-level-add-subdirs-to-load-path)) ; http://emacswiki.org/emacs/LoadPath#toc2

;;     ;; http://blog.jdhuntington.com/2008/11/emacs-color-theme-blackboard.html
;;     (autoload 'color-theme-blackboard "color-theme-blackboard" "color theme blackboard" t)
;;     ;; https://github.com/sellout/emacs-color-theme-solarized
;;     (autoload 'color-theme-solarized-light "color-theme-solarized" "color-theme-solarized-light" t)
;;     (autoload 'color-theme-solarized-dark "color-theme-solarized" "color-theme-solarized-dark" t)

;;     (eval-after-load "color-theme"
;;       '(progn
;;          (color-theme-initialize)
;;          (fset 'color-theme-snapshot (color-theme-make-snapshot))
;;          ;;(color-theme-hober)
;;          ;;(color-theme-blackboard)
;;          (color-theme-deep-blue)
;;          ))
;;     (autoload 'use-color-theme "color-theme-helper" "use specified color theme" t)
;;     ))

;; 输入vvn，然后按M-s <return>,就可以输入very-very-long-emacs-lisp-variable-name
;; https://github.com/baohaojun/bbyac/
(defun configure-bbyac ()
  (when (add-package 'bbyac bbyac-path)
    (require 'bbyac)
    (bbyac-global-mode 1)
    )
  )


;; https://github.com/auto-complete/auto-complete
(defun configure-auto-complete ()
  (when (add-package 'auto-complete auto-complete-path)
    
    (require 'auto-complete-config)
    ;; 如果是从包管理器里安装的，ac-dictionary-directories就已经被设置好了，无需自己设置
    (unless (package-installed-p 'auto-complete)
      (add-to-list 'ac-dictionary-directories (concat auto-complete-path "ac-dict"))
      )
    (ac-config-default)
    )
  )
;; (configure-auto-complete)



;; 输入几个字母，展开成一大片代码
;; https://github.com/joaotavora/yasnippet
(defun configure-yasnippet ()
  (when (add-package 'yasnippet yasnippet-path)
    (require 'yasnippet)
    (yas-global-mode 1)
    )
  )
;; (configure-yasnippet)



(defun configure-visual-basic-mode ()
  (if (not (file-exists-p visual-basic-mode-path))
      (message "no visual-basic-mode")
    (add-to-load-path visual-basic-mode-path)
    (autoload 'visual-basic-mode "visual-basic-mode" "Visual Basic mode." t)
    (add-to-list 'auto-mode-alist '("\\.vbs\\'" . visual-basic-mode))
    (add-to-list 'auto-mode-alist '("\\.vb\\'" . visual-basic-mode))
    (add-to-list 'auto-mode-alist '("\\.bas\\'" . visual-basic-mode))
    (add-to-list 'auto-mode-alist '("\\.frm\\'" . visual-basic-mode))
    (add-to-list 'auto-mode-alist '("\\.cls\\'" . visual-basic-mode))))


(defun configure-c++-mode ()
  (load "c++-helper.el" nil t t)
  (autoload 'make-guard "c++-helper" "make guard in C++ header" t)
  (autoload 'rebuild-and-reload-BROWSE "c++-helper" "rebuild and reload BROWSE" t)
  (autoload 'fix-enum-class "c++-helper" "Setup `c++-mode' to better handle \"class enum\"." t)
  (add-to-list 'auto-mode-alist '("\\.h\\'" . c++-mode))
  (add-hook 'c++-mode-hook 'tweak-c++-mode))


(defun configure-java-mode ()
  (add-hook 'java-mode-hook 'tweak-java-mode)
  )


(defun configure-python-mode ()
  (add-hook 'python-mode-hook
            '(lambda ()
               (define-key python-mode-map "\C-c\C-c" 'comment-region)))
  (add-to-list 'auto-mode-alist '("\\.pyw\\'" . python-mode))
  )


(defun configure-emacs-lisp-mode ()
  ;;(message "configure-emacs-lisp-mode")
  (add-hook 'emacs-lisp-mode-hook 'tweak-emacs-lisp-mode))


(defun configure-haskell-mode ()
  (when (add-package 'haskell-mode haskell-mode-path)
    (require 'haskell-interactive-mode)
    (require 'haskell-process)
    (add-hook 'haskell-mode-hook 'tweak-haskell-mode)
    (add-to-list 'auto-mode-alist '("\\.hs\\'" . haskell-mode))
    )
  )

(defun configure-go-mode ()
  (when (add-package 'go-mode "~/non-exist")
    (add-to-list 'auto-mode-alist '("\\.go\\'" . go-mode))
    (add-hook 'go-mode-hook
              '(lambda ()
                 (electric-pair-mode 1)))

    )
 )


(defun configure-ntcmd-mode ()
  (when (add-package 'ntcmd ntcmd-path)
    (add-to-list 'auto-mode-alist '("\\.bat\\'" . ntcmd-mode))
    (autoload 'ntcmd-mode "ntcmd" "ntcmd-mode" t))
  )


(defun configure-powershell ()
  ;; 在emacs中运行powershell
  ;; M-x powershell 即可
  (if (not (file-exists-p powershell-path))
      (message "no powershell")
    (add-to-load-path powershell-path)
    (autoload 'powershell "Powershell" "powershell" t)))


(defun configure-powershell-mode ()
  ;; powershell脚本模式
  (if (not (file-exists-p powershell-mode-path))
      (message "no powershell-mode")
    (add-to-load-path powershell-mode-path)
    (autoload 'powershell-mode "powershell-mode" "powershell-mode" t)
    (add-to-list 'auto-mode-alist '("\\.ps1\\'" . powershell-mode))))


(defun configure-markdown-mode ()
  (when (add-package 'markdown-mode markdown-mode-path)
    (autoload 'markdown-mode "markdown-mode.el" "Major mode for editing Markdown files" t)
    (add-to-list 'auto-mode-alist '("\\.md\\'" . markdown-mode))
    (add-to-list 'auto-mode-alist '("\\.markdown\\'" . markdown-mode))
    ;;(setq markdown-command "cmark")
    (add-hook 'markdown-mode-hook
              (lambda ()
                (ws-mode 1)))

    )
  )
;; (configure-markdown-mode)


(defun configure-yaml-mode ()
  (when (add-package 'yaml-mode yaml-mode-path)
    (autoload 'yaml-mode "yaml-mode.el" "Major mode for editing YAML files" t)
    (add-to-list 'auto-mode-alist '("\\.yaml\\'" . yaml-mode))
    (add-to-list 'auto-mode-alist '("\\.yml\\'" . yaml-mode))
    (add-hook 'yaml-mode-hook
              '(lambda ()
                 (define-key yaml-mode-map "\C-c\C-c" 'comment-region))))
  
  )


;;(configure-cmake-mode)
(defun configure-cmake-mode ()
  (when (add-package 'cmake-mode cmake-mode-path)
    (autoload 'cmake-mode "cmake-mode.el" "Major mode for editing CMake listfiles." t)
    (add-to-list 'auto-mode-alist '("CMakeLists\\.txt\\'" . cmake-mode))
    (add-to-list 'auto-mode-alist '("\\.cmake\\'" . cmake-mode))
    
    (add-hook 'cmake-mode-hook
              '(lambda ()
                 (define-key cmake-mode-map "\C-c\C-c" 'comment-region)))
    )
  )


(defun configure-weibo ()
  (when (add-package 'weibo weibo-path)
    (autoload 'weibo-timeline "weibo.el" "sina weibo" t)
    ;; (require 'weibo)
    )
  )


;; 这个插件可以让emacs在打开文件时，自动检测文件的编码，避免乱码
;; https://www.emacswiki.org/emacs/Unicad
(defun configure-unicad ()
  (when (add-package 'unicad unicad-path)
    (require 'unicad)
    )
  )

(defun configure-html-mode ()
  (add-hook 'html-mode-hook
            '(lambda ()
               (define-key html-mode-map "\C-c\C-c" 'comment-region)
               ))
  )

(defun configure-web-mode ()
  (when (add-package 'web-mode web-mode-path)
    (require 'web-mode)
    (add-to-list 'auto-mode-alist '("\\.phtml\\'" . web-mode))
    (add-to-list 'auto-mode-alist '("\\.tpl\\.php\\'" . web-mode))
    (add-to-list 'auto-mode-alist '("\\.[gj]sp\\'" . web-mode))
    (add-to-list 'auto-mode-alist '("\\.as[cp]x\\'" . web-mode))
    (add-to-list 'auto-mode-alist '("\\.erb\\'" . web-mode))
    (add-to-list 'auto-mode-alist '("\\.mustache\\'" . web-mode))
    (add-to-list 'auto-mode-alist '("\\.djhtml\\'" . web-mode))
    (add-to-list 'auto-mode-alist '("\\.html?\\'" . web-mode))
    (add-hook 'web-mode-hook
            '(lambda ()
               (electric-pair-mode 1)))
    )
  )

(defun configure-js-mode ()
  (add-hook 'js-mode-hook
            '(lambda ()
               (electric-pair-mode 1)
               (setq js-indent-level 2)

               (subword-mode 1)           ; 视大写字母为word的边界，helloWorldChina
               (ws-mode)                  ; 中文分词
               (pmh-mode)
               ;; 在汉字中启用ws-mode，在英文中启用subword-mode
               (add-hook 'pmh-hook '(lambda ()
                                      (if (looking-at "\\cc")
                                          (progn
                                            (setq subword-mode nil)
                                            (setq ws-mode t)
                                            )
                                        (setq subword-mode t)
                                        (setq ws-mode nil)))
                         nil
                         t
                         )
               
               ))
  )

(defun configure-js2-mode ()
  (add-to-list 'auto-mode-alist '("\\.js\\'" . js2-mode))
  ;; (autoload 'stringify "js-helper" "quote a region" t)
  (load "js-helper.el" nil t t)
  (add-hook 'html-mode-hook
            '(lambda ()
               (define-key html-mode-map "\C-cs" 'stringify)
               )
            )
  (add-hook 'js2-mode-hook
            '(lambda ()
               (define-key js2-mode-map "\C-cs" 'stringify)
               (setq js2-basic-offset 2)
               (electric-pair-mode 1)
               ;; (require 'bbyac)
               ;; (bbyac-mode 1)
               (define-key js2-mode-map "\C-c\C-c" 'comment-region)
               (define-key js2-mode-map "\C-ca" 'align-regexp)
               ;; (define-key js2-mode-map "\C-cs" 'stringify)

               (subword-mode 1)           ; 视大写字母为word的边界，helloWorldChina
               (ws-mode)                  ; 中文分词
               (pmh-mode)
               ;; 在汉字中启用ws-mode，在英文中启用subword-mode
               (add-hook 'pmh-hook '(lambda ()
                                      (if (looking-at "\\cc")
                                          (progn
                                            (setq subword-mode nil)
                                            (setq ws-mode t)
                                            )
                                        (setq subword-mode t)
                                        (setq ws-mode nil)))
                         nil
                         t
                         )


               ))
  )

(defun configure-css-mode ()
    (add-hook 'css-mode-hook
            '(lambda ()
               (define-key css-mode-map "\C-c\C-c" 'comment-region)))
  )


;; 要用这个东西还得先通过npm安装https://github.com/clausreinke/typescript-tools
(defun configure-tss-mode ()
	(when (add-package 'tss-mode "~/non-exist")
  ;; 以下配置是从https://github.com/aki2o/emacs-tss 直接抄过来的
  ;; If use bundled typescript.el,
  (require 'typescript)
  (add-to-list 'auto-mode-alist '("\\.ts\\'" . typescript-mode))

  ;; (require 'tss)

  ;; ;; Key binding
  ;; (setq tss-popup-help-key "C-:")
  ;; (setq tss-jump-to-definition-key "C->")
  ;; (setq tss-implement-definition-key "C-c i")

  ;; Make config suit for you. About the config item, eval the following sexp.
  ;; (customize-group "tss")

  ;; ;; Do setting recommemded configuration
  ;; (tss-config-default)

  (add-hook 'typescript-mode-hook
            '(lambda ()
               (setq typescript-indent-level 2)
               (electric-pair-mode 1)
               (define-key typescript-mode-map "\C-c\C-c" 'comment-region)
               (define-key typescript-mode-map "\C-ca" 'align-regexp)

               (subword-mode 1)           ; 视大写字母为word的边界，helloWorldChina
               (ws-mode)                  ; 中文分词
               (pmh-mode)
               ;; 在汉字中启用ws-mode，在英文中启用subword-mode
               (add-hook 'pmh-hook '(lambda ()
                                      (if (looking-at "\\cc")
                                          (progn
                                            (setq subword-mode nil)
                                            (setq ws-mode t)
                                            )
                                        (setq subword-mode t)
                                        (setq ws-mode nil)))
                         nil
                         t
                         )


               ))

	)
  
  )

;; 按C-c SPC后输入屏幕上的一个字母，立即移动到该字母处。
;; https://github.com/winterTTr/ace-jump-mode/wiki
;; 安装ace-jump-mode时请一并安装ace-pinyin，可按拼音首字母跳跃。
(defun configure-ace-jump-mode ()
  (when (add-package 'ace-jump-mode ace-jump-mode-path)
    (require 'ace-jump-mode)
    ;; (define-key global-map (kbd "C-c SPC") 'ace-jump-mode)
    (when (add-package 'ace-pinyin "~/non-exist")
      (define-key global-map (kbd "C-c j") 'ace-pinyin-dwim) ; 需安装ace-pinyin
      )
    )
  )
;; (configure-ace-jump-mode)


;; 按C-x o后，输入窗口标号，立即切换到该窗口
(defun configure-ace-window ()
  (when (add-package 'ace-window "~/non-exist")
    (global-set-key (kbd "C-x o") 'ace-window)
    )
  )
;; (configure-ace-window)

;; (configure-tabbar-mode)
(defun configure-tabbar-mode ()
  (when (add-package 'tabbar "~/non-exist") ; 注意：人家provide的是tabbar，而非tabbar-mode
    (require 'tabbar)
    ;;(setq tabbar-mode t) ; 文档说设置这个变量没用
    (tabbar-mode)
    )
  )


;; 例子
;; (defun foo ()
;;    (if (f 5)
;;        (let ((a 1))
;;          |(bar a)) ;; M-x paredit-convolute-sexp, | stands for the cursor
;;      (qux 2))) 
;; 变成
;; (defun foo ()
;;   (let ((a 1))
;;     (if (f 5) 
;;         (bar a)
;;       (qux 2))))
(defun configure-paredit ()
  (when (add-package 'paredit paredit-path)
    (autoload 'paredit-mode "paredit"
      "Minor mode for pseudo-structurally editing Lisp code." t))
  )


(defun configure-xcscope ()
  (when (add-package 'xcscope xcscope-path)
    (require 'xcscope)
    )
  )


;; 我自己的C++项目build system
;; https://gitee.com/duyanning/epm
;; 使用前需要做的事情：
;;   安装好epm：
;;     ~/work$ git clone git@gitee.com:duyanning/epm.git
;;     在.bashrc中增加 PATH="$HOME/work/epm:$PATH"
;;     确保epm help能够执行
;;   安装好pymacs(emacs需要用它来调用epm的python代码)：
;;     sudo apt install pymacs
;; 快捷键：
;;   C-f7	compile current C++ file
;;   f7		build project
(defun configure-epm ()
  (if (not (file-exists-p epm-path))
      (message "no epm")
    (load (concat epm-path "epmacs"))
    ;;(load (concat "/home/duyanning/work/epm/" "epmacs"))
    (global-set-key [f7] 'epm-build)
    (global-set-key [C-f7] 'epm-compile)
    (global-set-key [f5] 'epm-run-gdb)))
;; (configure-epm)

(defun configure-calendar/diary ()
  (setq appt-display-format 'window)
  (appt-activate)
  ;; appt-audible
  ;; appt-display-duration
  ;; appt-disp-window-function
  ;; appt-delete-window-function
  ;; appt-message-warning-time
  ;; (setq appt-display-diary nil)
  )


;;;; 挂在hook上的各种微调（以tweak打头）。如果短而简单，
;;;; 就直接放在configure函数中的lambda中；如果长而复杂，才在此处建立专
;;;; 门的tweak函数。

(defun tweak-org-mode ()
  (visual-line-mode)

  ;; (require 'smart-kill)
  ;; (turn-on-smart-kill)

  (ws-mode 1)
  (org-indent-mode 1)

  ;; handle conflict between smart-kill-mode and ws-mode on M-d
  ;; (define-key smart-kill-mode-map "\M-d" 'ws-smart-kill-word)
  ;; (define-key ws-mode-map "\M-d" 'ws-smart-kill-word)

  )

(defun tweak-TeX-mode ()
  (TeX-source-correlate-mode)
  ;;TeX-source-correlate-method


  ;; reftex的toc远比outline模式好用
  ;;(outline-minor-mode 1)
  (turn-on-reftex)

  (visual-line-mode)

  ;; (require 'smart-kill)
  ;; (turn-on-smart-kill)

  (ws-mode 1)

  ;; ;; handle conflict between smart-kill-mode and ws-mode on M-d
  ;; (define-key smart-kill-mode-map "\M-d" 'ws-smart-kill-word)
  ;; (define-key ws-mode-map "\M-d" 'ws-smart-kill-word)

  (define-key TeX-mode-map (kbd "<f12>") 'toggle-line-spacing)

  )


(defun tweak-emacs-lisp-mode ()
  (message "tweak-emacs-lisp-mode")
  (define-key emacs-lisp-mode-map "\C-c\C-c" 'comment-region)
  (ws-mode)                             ; 中文分词

  (when (add-package 'paredit paredit-path)
    (paredit-mode +1)  
    (pmh-mode t)
    ;; 在汉字中启用ws-mode，在英文中启用paredit-mode 
    ;; todo: paredit-mode非自带，需要先检测
    (add-hook 'pmh-hook '(lambda ()
                           (if (looking-at "\\cc")
                               (progn
                                 (setq paredit-mode nil)
                                 (setq ws-mode t)
                                 )
                             (setq paredit-mode +1)
                             (setq ws-mode nil)))
              nil
              t
              )
    )
  )


(defun tweak-c++-mode ()
  ;;(buffer-face-mode -1)
  ;;(buffer-face-set 'c++mode)



  ;;HelloWorld
  ;; glass-mode

  ;;我要按照<<Code Complete>>的建议在缩进的注释中写伪代码，/会导致当前行被自动缩进
  (c-toggle-electric-state 1)
  ;;(c-toggle-electric-state -1)
  ;;(setq c-syntactic-indentation nil)

  (fix-enum-class)
  (font-lock-add-keywords 'c++-mode
                          '(("constexpr" . 'font-lock-keyword-face)))
  (font-lock-add-keywords 'c++-mode
                          '(("override" . 'font-lock-keyword-face)))



  (subword-mode 1)           ; 视大写字母为word的边界，helloWorldChina
  (ws-mode)                  ; 中文分词
  (pmh-mode)
  ;; 在汉字中启用ws-mode，在英文中启用subword-mode
  (add-hook 'pmh-hook '(lambda ()
                         (if (looking-at "\\cc")
                             (progn
                               (setq subword-mode nil)
                               (setq ws-mode t)
                             )
                           (setq subword-mode t)
                           (setq ws-mode nil)))
            nil
            t
            )


  ;; ws-mode可以和我的smart-kill-mode共存
  ;; subword-mode可以和我的smart-kill-mode共存
  ;; 但不要在同一个buffer中同时启用ws-mode与subword-mode
  ;; smart-kill-mode conflicts with subword-mode
  ;; reason: kill-word-without-kill-ring uses kill-word
  ;; (require 'smart-kill)
  ;; (turn-on-smart-kill)
  ;; ;; handle conflict between smart-kill-mode and subword-mode on M-d
  ;; (define-key smart-kill-mode-map "\M-d" 'smart-kill-subword)
  ;; (define-key subword-mode-map "\M-d" 'smart-kill-subword)

  (local-set-key (kbd "<f4>") 'rebuild-and-reload-BROWSE)



  )


(defun tweak-java-mode ()
  (electric-pair-mode 1)
  (subword-mode 1)           ; 视大写字母为word的边界，helloWorldChina
  (ws-mode)                  ; 中文分词
  (pmh-mode)
  ;; 在汉字中启用ws-mode，在英文中启用subword-mode
  (add-hook 'pmh-hook '(lambda ()
                         (if (looking-at "\\cc")
                             (progn
                               (setq subword-mode nil)
                               (setq ws-mode t)
                               )
                           (setq subword-mode t)
                           (setq ws-mode nil)))
            nil
            t
            )
  )


(defun tweak-haskell-mode ()
  (haskell-indentation-mode)
  (interactive-haskell-mode)


  (define-key haskell-mode-map (kbd "C-c C-l") 'haskell-process-load-or-reload)
  ;;(define-key haskell-mode-map (kbd "C-`") 'haskell-interactive-bring)
  (define-key haskell-mode-map (kbd "C-c C-t") 'haskell-process-do-type)
  (define-key haskell-mode-map (kbd "C-c C-i") 'haskell-process-do-info)
  ;;(define-key haskell-mode-map (kbd "C-c C-c") 'haskell-process-cabal-build)
  ;;(define-key haskell-mode-map (kbd "C-c C-k") 'haskell-interactive-mode-clear)
  ;;(define-key haskell-mode-map (kbd "C-c c") 'haskell-process-cabal)


  (define-key haskell-mode-map "\C-c\C-c" 'comment-region)
  ;; 光在haskell-mode-map中定义组合键没用，因为interactive-haskell-mode也会定义这些组合键，要改一起改
  (define-key interactive-haskell-mode-map "\C-c\C-c" 'comment-region)

  (haskell-doc-mode)

  ;;(turn-on-haskell-indent)


  (subword-mode 1)  
  (ws-mode)                             ; 中文分词
  (pmh-mode)
  ;; 在汉字中启用ws-mode，在英文中启用subword-mode 
  (add-hook 'pmh-hook '(lambda ()
                         (if (looking-at "\\cc")
                             (progn
                               (setq subword-mode nil)
                               (setq ws-mode t))
                           (setq subword-mode t)
                           (setq ws-mode nil)))
            nil
            t)

    (when (add-package 'paredit paredit-path)
      (paredit-mode +1)  
    )

  )




;;;; 下面是M-x customize生产的

(custom-set-variables
 ;; custom-set-variables was added by Custom.
 ;; If you edit it by hand, you could mess it up, so be careful.
 ;; Your init file should contain only one such instance.
 ;; If there is more than one, they won't work right.
 '(column-number-mode t)
 '(package-selected-packages
   (quote
    (magit chinese-pyim-basedict chinese-pyim tss org-plus-contrib ntcmd helm bbyac ace-window ace-pinyin)))
 '(show-paren-mode t))
;; (custom-set-faces
;;  ;; custom-set-faces was added by Custom.
;;  ;; If you edit it by hand, you could mess it up, so be careful.
;;  ;; Your init file should contain only one such instance.
;;  ;; If there is more than one, they won't work right.
;;  '(default ((t (:family "Consolas" :foundry "outline" :slant normal :weight normal :height 143 :width normal))))
;;  '(table-cell ((t (:background "pale goldenrod" :foreground "black" :inverse-video nil))) t))
  
(custom-set-faces
 ;; custom-set-faces was added by Custom.
 ;; If you edit it by hand, you could mess it up, so be careful.
 ;; Your init file should contain only one such instance.
 ;; If there is more than one, they won't work right.
 '(default ((t (:family "Yahei Mono" :foundry "MS  " :slant normal :weight normal :height 128 :width normal)))))
(put 'upcase-region 'disabled nil)
(put 'downcase-region 'disabled nil)


;; ;;; This was installed by package-install.el.
;; ;;; This provides support for the package system and
;; ;;; interfacing with ELPA, the package archive.
;; ;;; Move this code earlier if you want to reference
;; ;;; packages in your .emacs.
;; (when
;;     (load
;;      (expand-file-name "~/.emacs.d/elpa/package.el"))
;;   (package-initialize))



;; 调整默认字体大小后再最大化窗口，所以将主入口放在自动生成的配置之后。
;;;; 主入口（main entry）
;;;; 下列is-xxx函数的顺序很重要，因为有可能多个is-xxx都为真。
(cond 
 ((is-wsl) (load-wsl-settings))        ; WSL
 ((is-ubuntu) (load-ubuntu-settings))  ; Ubuntu
 ((is-winxp) (load-winxp-settings))    ; Windows XP
 ((is-win7) (load-win7-settings))      ; Windows 7+
 ((is-win10) (load-win7-settings))      ; Windows 10
 ((is-cygwin) (load-cygwin-settings))  ; Cygwin
 ((is-term) (load-term-settings))      ; character only terminal
 )
